/*
Copyright (C) 2008  Helmut Juskewycz
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.juskewycz.dividere.action.split;

import com.juskewycz.dividere.action.ProgressStatus;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Implements <code>ISplitter</code> and uses one thread for the splitting.
 * 
 * @author Helmut Juskewycz
 * @createdon 27. January 2008
 * @lastmodified 27. January 2008
 * @history
 * 27. January 2008 Finished version 1.0
 */
public class OneThreadBufferSplitter extends ASplitter {

    private static final Logger logger = Logger.getLogger(OneThreadBufferSplitter.class.getName());

    @Override
    public void split(String filePath, long splitSize) {

	if (!validSplitterInputArgumtents(filePath, splitSize)) {
	    return;
	}

	InputStream in = null;
	try {
	    File originalFile = new File(filePath);
	    if (!checkSplitFileExists(originalFile)) {
		return;
	    }

	    final long wholeFileSize = originalFile.length();
	    final int piecesNumber = (int) (wholeFileSize / splitSize + 1);
	    in = new FileInputStream(originalFile);

	    notifySplitBegin(originalFile);
	    notifyProgressListeners(new ProgressStatus(0, piecesNumber, ""));
	    List<File> splittedFiles = new ArrayList<File>();
	    for (int i = 1; i <= piecesNumber; i++) {
		File filePiece = new File(createSplitFilePath(filePath, i));
		notifySplitPartBegin(i, filePiece);
		if (filePiece.createNewFile()) {
		    OutputStream out = null;
		    try {
			out = new FileOutputStream(filePiece);
			long readBytes = 0;
			while ((readBytes + BUFF_SIZE) < splitSize) {
			    synchronized (buffer) {
				int amountRead = in.read(buffer);
				if (amountRead == -1) {
				    break;
				}
				out.write(buffer, 0, amountRead);
				readBytes += amountRead;
			    }
			}

			byte[] restBuffer = new byte[(int) (splitSize - readBytes)];
			int amountRead = in.read(restBuffer);
			if (amountRead != -1) {
			    out.write(restBuffer, 0, amountRead);
			}
			restBuffer = null;
			out.close();
			out = null;
			notifySplitPartEnd(i, filePiece);
			notifyProgressListeners(new ProgressStatus(i, piecesNumber, filePiece.getPath()));
			splittedFiles.add(filePiece);
		    } finally {
			if (out != null) {
			    out.flush();
			    out.close();
			    out = null;
			}
		    }
		} else {
		    errorCanNotCreatePartFile(filePiece.getPath(), piecesNumber, i);
		    //delete the already splitted files
		    for (File file : splittedFiles) {
			file.delete();
		    }
		    //stop splitting
		    break;
		}
	    }
	    in.close();
	    in = null;
	    notifySplitEnd(originalFile);
	} catch (IOException ex) {
	    logger.log(Level.SEVERE, null, ex);
	    notifyError(new ProgressStatus(0, 0, ERROR_FILE_IO, true));
	} finally {
	    try {
		if (in != null) {
		    in.close();
		}
	    } catch (IOException ex) {
		logger.log(Level.SEVERE, null, ex);
	    }
	}
    }
}
